package logger

import (
	"gitee.com/liukexing/mqbroker/core/driver/config"
	"gitee.com/liukexing/mqbroker/core/typedef"
	"log"
	"path/filepath"
	"runtime"
	"time"
)

const (
	ConfigName = "config.core.driver.logger"
)

var (
	logTypes map[string]typedef.LoggerTypeInfo
	Config   typedef.ConfigInfo
	logMaps  map[string]typedef.LogConfig
)

func init() {
	initTypes()
	var ok bool
	Config, ok = config.GetConfig(ConfigName)
	if !ok {
		return
	}
	initMaps()
	config.Log = Log
}

func initTypes() {
	logTypes = make(map[string]typedef.LoggerTypeInfo)
	logTypes["Verbose"] = typedef.VERBOSE
	logTypes["Debug"] = typedef.DEBUG
	logTypes["Info"] = typedef.INFO
	logTypes["Warn"] = typedef.WARN
	logTypes["Error"] = typedef.ERROR
	logTypes["Assert"] = typedef.ASSERT
}

func initMaps() {
	logMaps = make(map[string]typedef.LogConfig)
	RegisterLogHandle("common", CommLog)

}

func RegisterLogHandle(name string, logfun typedef.LogHandle) {
	temp := typedef.LogConfig{
		Handel: logfun,
		Config: make(map[string][]string),
	}
	if err := typedef.Decode(Config.Extend[name], &temp.Config); err != nil {
		CommLog(typedef.LoggerInfo{
			Type:      typedef.ERROR,
			Info:      Config.Info,
			Run:       typedef.LoggerRunInfo{},
			Message:   err,
			Timestamp: time.Now().Unix(),
		})
		return
	}
	logMaps[name] = temp
}

func CommLog(info typedef.LoggerInfo) {
	log.Printf("[%s][%s][%s:%d:%s]%v\n", info.Type.Name, info.Info.Module, info.Run.File, info.Run.Line, info.Run.Func, info.Message)
}

func Log(info typedef.LoggerInfo) {
	if len(logMaps) == 0 {
		CommLog(info)
		return
	}
	for _, v := range logMaps {
		for _, tps := range v.Config[Config.Extend["level"].(string)] {
			if tps == "All" {
				v.Handel(info)
				break
			}
			if k, ok := logTypes[tps]; ok && k.Name == info.Type.Name {
				v.Handel(info)
				break
			}
		}
	}
}
func runinfo() typedef.LoggerRunInfo {
	run := typedef.LoggerRunInfo{
		File: "???",
		Line: 0,
		Func: "???",
	}
	pc, filename, line, ok := runtime.Caller(2)
	if ok {
		run.Func = filepath.Base(runtime.FuncForPC(pc).Name())
		run.File = filepath.Base(filename)
		run.Line = line
	}
	return run
}
func CheckErr(err typedef.ErrInfo) bool {
	if err.Err != nil {
		Log(typedef.LoggerInfo{
			Type:      typedef.ERROR,
			Info:      err.Info,
			Run:       runinfo(),
			Message:   err.Err,
			Timestamp: time.Now().Unix(),
		})
	}
	return err.Err != nil
}
func Verbose(verbose typedef.CommInfo) {
	Log(typedef.LoggerInfo{
		Type:      typedef.VERBOSE,
		Info:      verbose.Info,
		Run:       runinfo(),
		Message:   verbose.Message,
		Timestamp: time.Now().Unix(),
	})
}
func Debug(debug typedef.CommInfo) {
	Log(typedef.LoggerInfo{
		Type:      typedef.DEBUG,
		Info:      debug.Info,
		Run:       runinfo(),
		Message:   debug.Message,
		Timestamp: time.Now().Unix(),
	})
}
func Info(info typedef.CommInfo) {
	Log(typedef.LoggerInfo{
		Type:      typedef.INFO,
		Info:      info.Info,
		Run:       runinfo(),
		Message:   info.Message,
		Timestamp: time.Now().Unix(),
	})
}
func Warn(warn typedef.CommInfo) {
	Log(typedef.LoggerInfo{
		Type:      typedef.WARN,
		Info:      warn.Info,
		Run:       runinfo(),
		Message:   warn.Message,
		Timestamp: time.Now().Unix(),
	})
}
func Error(err typedef.ErrInfo) {
	if err.Err != nil {
		Log(typedef.LoggerInfo{
			Type:      typedef.ERROR,
			Info:      err.Info,
			Run:       runinfo(),
			Message:   err.Err,
			Timestamp: time.Now().Unix(),
		})
	}
}
func Assert(assert typedef.CommInfo) {
	Log(typedef.LoggerInfo{
		Type:      typedef.ASSERT,
		Info:      assert.Info,
		Run:       runinfo(),
		Message:   assert.Message,
		Timestamp: time.Now().Unix(),
	})
}
